package cn.stylefeng.guns.modular.business.util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.stylefeng.guns.core.context.login.LoginContextHolder;
import cn.stylefeng.guns.core.enums.CoreExceptionEnum;
import cn.stylefeng.guns.core.exception.CustomException;
import cn.stylefeng.guns.core.pojo.login.SysLoginUser;
import cn.stylefeng.guns.core.pojo.response.ResponseData;
import cn.stylefeng.guns.modular.business.app.pay.WxPaySendData;
import cn.stylefeng.guns.modular.business.app.pay.WxRefundData;
import cn.stylefeng.guns.modular.business.custom.constant.Token;
import cn.stylefeng.guns.modular.business.frequency.appmessage.model.param.AppMessageParam;
import cn.stylefeng.guns.modular.business.frequency.appmessage.service.AppMessageService;
import cn.stylefeng.guns.modular.business.frequency.ordersub.entity.OrderSub;
import cn.stylefeng.guns.modular.business.frequency.siterelation.entity.SiteRelation;
import cn.stylefeng.guns.modular.business.frequency.siterelation.service.SiteRelationService;
import cn.stylefeng.guns.modular.util.HttpRequestUtil;
import cn.stylefeng.guns.modular.util.MD5EncryptionPwdUtil;
import cn.stylefeng.guns.modular.util.MD5Util;
import cn.stylefeng.guns.sys.modular.emp.service.SysEmpService;
import cn.stylefeng.guns.sys.modular.user.entity.SysTenant;
import cn.stylefeng.guns.sys.modular.user.entity.SysUser;
import cn.stylefeng.guns.sys.modular.user.service.SysTenantService;
import cn.stylefeng.guns.sys.modular.user.service.SysUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
import lombok.extern.slf4j.Slf4j;
import net.sf.jxls.transformer.XLSTransformer;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author 刘耀
 * @Date 2020/9/16 14:24
 */
@Slf4j
@Component
public class BusinessUtil {

    private static String GENERATE_ORDER_NO_KEY = "generate_order_key";


    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SiteRelationService siteRelationService;

    @Autowired
    private SysEmpService sysEmpService;

    @Autowired
    private SysTenantService sysTenantService;

    @Resource
    private SysUserService sysUserService;


    @Resource
    private AppMessageService appMessageService;


    @Value("${wxrefundfile.path}")
    private String refundFile;

    public static String getFormatBeginTime(Date time) {
        if (time != null) {
            return DateUtil.format(DateUtil.beginOfDay(DateUtil.offsetDay(time, 0)), "yyyy-MM-dd HH:mm:ss");
        } else {
            return null;
        }
    }

    public static String getFormatTime(Date time) {
        if (time != null) {
            return DateUtil.format(time, "yyyy-MM-dd HH:mm:ss");
        } else {
            return null;
        }
    }

    public static <T> Object getFieldValue(T obj, String filedName) {
        try {
            Class<?> clazz = obj.getClass();
            Field field = clazz.getDeclaredField(filedName);
            field.setAccessible(true);
            return field.get(obj);

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            return null;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据特定业务编号，prefix为业务代码
     *
     * @param tenantId
     * @return
     */

    public String getOrderNo(Long tenantId) {
        return getSeqNo(GENERATE_ORDER_NO_KEY, tenantId);
    }

    private String getSeqNo(String key, Long tenantId) {
        key = key + tenantId;
        RedisAtomicLong redisAtomicLong;
        if (!redisTemplate.hasKey(key)) {
            // 如果不存在 则去数据库中查找
            String orderNo = sysEmpService.getLastOrderNo(tenantId);
            Long initValue = null;
            if (orderNo == null) {
                initValue = 100000l;
            } else {
                initValue = Long.parseLong(orderNo.split("-")[0]);
            }
            log.info("======初始化订单号：" + initValue);
            redisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory(), initValue);
        } else {
            redisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
        }
        return String.valueOf(redisAtomicLong.incrementAndGet());
    }

    private void degreesNo(String key, String prefix) {
        RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
        redisAtomicLong.decrementAndGet();
    }

    /**
     * 获取用户数据权限
     *
     * @return
     */
    public List<Long> getEmpByOrgList() {
        return sysEmpService.getEmpByOrgList();
    }

    public List<Long> getEmpByOrgId(Long orgId) {
        return sysEmpService.getEmpByOrgId(orgId);
    }


    /**
     * 获取租户号
     *
     * @return
     */
    public Long getTenantId() {
        if (LoginContextHolder.me().isSuperAdmin()) {
            return 1l;
        } else {
            SysLoginUser loginUser = LoginContextHolder.me().getSysLoginUser();
            return loginUser.getTenantId();
        }
    }

    public String getTenantName() {
        SysTenant tenantInfo = getTenantInfo();
        if (tenantInfo == null) {
            return null;
        }
        return tenantInfo.getName();
    }

    public String getTenantCompanyName() {
        SysTenant tenantInfo = getTenantInfo();
        if (tenantInfo == null) {
            return null;
        }
        return tenantInfo.getCompanyName();
    }

    /**
     * 获取租户信息
     */
    public SysTenant getTenantInfo() {
        if (getTenantId() == 1L) {
            log.info("==========超级管理员===========");
        }
        return sysTenantService.getOne(new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getId, getTenantId()));
    }


    public String getContractSignImg() {
        String signImg = getTenantInfo().getContractSignImg();
        if (!StringUtils.isBlank(signImg)) {
            return signImg;
        }
        return "";
    }


    public SiteRelation getSiteInfo() {

        SiteRelation relation = siteRelationService.getOne(new LambdaQueryWrapper<SiteRelation>()
                .eq(SiteRelation::getUserId, LoginContextHolder.me().getSysLoginUserId())
                .eq(SiteRelation::getTenantId, getTenantId())
        );

        return relation;
    }

    public Long getSiteId() {
        SiteRelation siteInfo = getSiteInfo();
        if (siteInfo == null) {
            return null;
        } else {
            return siteInfo.getSiteId();
        }
    }

    /**
     * 拼接字符串
     *
     * @param list   集合
     * @param prefix 符号
     * @return
     */
    public String jointString(List<?> list, String prefix) {
        StringBuilder joinString = new StringBuilder();
        if (list.size() > 0) {
            for (Object object : list) {
                if (object != null) {
                    joinString.append(object.toString()).append(prefix);
                }
            }
            joinString.deleteCharAt(joinString.length() - 1);
            return joinString.toString();
        } else {
            return "";
        }

    }

    /**
     * 功能描述:微信退款
     *
     * @param data
     * @param key
     * @return
     * @author yanzy  2016-10-25 下午01:52:19
     */
    public WxRefundData refund(WxRefundData data, String key) {
        String returnXml = null;
        WxRefundData reData = null;
        try {
            //生成sign签名
            SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
            parameters.put("appid", data.getAppid());
            parameters.put("mch_id", data.getMch_id());
            parameters.put("nonce_str", data.getNonce_str());
            parameters.put("out_trade_no", data.getOut_trade_no());
            parameters.put("out_refund_no", data.getOut_refund_no());
            parameters.put("total_fee", data.getTotal_fee());
            parameters.put("refund_fee", data.getRefund_fee());
            parameters.put("op_user_id", data.getOp_user_id());
            log.info("SIGN:" + createSign(parameters, key));
            data.setSign(createSign(parameters, key));
            XStream xs = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_")));
            xs.alias("xml", WxRefundData.class);
            String xml = xs.toXML(data);
            log.info("微信退款xml为:\n" + xml);
            //防止小程序和微信用不一样的参数 此处先判断
            returnXml = HttpRequestUtil.sendCertPostXml("https://api.mch.weixin.qq.com/secapi/pay/refund", data.getMch_id(), xml, refundFile);
            log.info("返回结果:" + returnXml);

            XStream xs1 = new XStream(new DomDriver());
            xs1.alias("xml", WxRefundData.class);
            reData = (WxRefundData) xs1.fromXML(returnXml);

            log.info("==========解析结果==============" + reData.getResult_code());
            return reData;

        } catch (Exception e) {
            e.printStackTrace();
        }
        reData = new WxRefundData();
        reData.setResult_code("FAIL");
        return reData;
    }

    public String createSign(SortedMap<Object, Object> parameters, String key) {
        StringBuffer sb = new StringBuffer();
        Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序（升序）
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            Object v = entry.getValue();
            if (null != v && !"".equals(v)
                    && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + key);
        String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();
        return sign;
    }

    /**
     * 功能描述:微信支付第一步——统一下单
     *
     * @param data
     * @param key
     * @return
     * @author yanzy  2016-1-18 下午10:01:20
     */
    public String unifiedOrder(WxPaySendData data, String key) {
        System.out.println("=========================data:" + data);
        System.out.println("=========================key:" + key);
        //统一下单支付
        String returnXml = null;
        try {
            //生成sign签名
            SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
            parameters.put("appid", data.getAppid());
            parameters.put("attach", data.getAttach());
            parameters.put("body", data.getBody());
//          parameters.put("key", data.getKey());
            parameters.put("mch_id", data.getMch_id());
            parameters.put("nonce_str", data.getNonce_str());
            parameters.put("notify_url", data.getNotify_url());
            parameters.put("openid", data.getOpenid());
            parameters.put("out_trade_no", data.getOut_trade_no());
            parameters.put("spbill_create_ip", data.getSpbill_create_ip());
            parameters.put("total_fee", data.getTotal_fee());
            parameters.put("trade_type", data.getTrade_type());
//            parameters.put("device_info", data.getDevice_info());
            //  data.setSign(WeiXinUtil.createSign(characterEncoding,parameters));
            data.setSign(createSign(parameters, key));

            XStream xs = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_")));
            xs.alias("xml", WxPaySendData.class);
            String xml = xs.toXML(data);
            returnXml = HttpRequestUtil.sendPostXml("https://api.mch.weixin.qq.com/pay/unifiedorder", xml);

            System.out.println("=============================返回结果:" + returnXml);
        } catch (Exception e) {
        }
        return returnXml;
    }

    /**
     * 根据模板生成Excel文件.
     *
     * @param templateFileName 模板文件.
     * @param list             模板中存放的数据.
     * @param resultFileName   生成的文件.
     */
    public void createExcel(String templateFileName, List<?> list, String resultFileName, HttpServletResponse
            response, String fileName) throws Exception {
        //创建XLSTransformer对象
        XLSTransformer transformer = new XLSTransformer();

        // 获取模板文件
        InputStream is = new FileInputStream(new File(templateFileName));
        //得到模板文件路径
        String srcFilePath = templateFileName;
        Map<String, Object> beanParams = new HashMap<String, Object>();
        beanParams.put("list", list);
        Workbook workbook = transformer.transformXLS(is, beanParams);
        String destFilePath = resultFileName + fileName + ".xlsx";
        try {
            //生成Excel文件
            transformer.transformXLS(srcFilePath, beanParams, destFilePath);
            //客户端
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8"));
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            workbook.write(response.getOutputStream());
            response.getOutputStream().close();
            //删除源文件
            File file = new File(fileName + ".xlsx");
            file.delete();
        } catch (Exception e) {
            e.printStackTrace();
        }
        is.close();
    }


    /**
     * 生成token
     *
     * @param userId 用户id
     * @return
     */
    public ResponseData getToken(Long userId, Integer userType) {

        //组装token
        String token = assembleToken(userType);

        redisTemplate.opsForValue().set(token, userId.toString(), Token.EXPIRE_SECOND, TimeUnit.DAYS);

        //存储token信息
        redisTemplate.opsForHash().put(Token.TOKEN_MAP, userId + "", token);


        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        return ResponseData.success(result);
    }


    /**
     * 组装token
     *
     * @param userType
     * @return
     */
    private String assembleToken(Integer userType) {

        String token = "";

        switch (userType) {
            case 1:
                token = Token.customer + UUID.randomUUID().toString();
                break;
            case 2:
                token = Token.master_worker + UUID.randomUUID().toString();
                break;
            default:
                throw new CustomException(CoreExceptionEnum.ERROR_PARAM);
        }
        return token;
    }


    /**
     * 判断登录密码是否错误
     *
     * @param userId
     * @param userType
     * @param pwd
     * @return
     */
    public Boolean loginPwdTrue(Long userId, Integer userType, String pwd) {

        String userPwd = "";

        //根据不同的用户类型 查询用户的密码
        switch (userType) {
            case 1:
                SysUser sysUser = sysUserService.getById(userId);
                userPwd = sysUser.getPassword();
                break;
            case 2:
                //MasterWorker masterWorker = masterWorkerService.getById(userId);
                //userPwd = masterWorker.getLoginPwd();
                break;
            default:
                throw new CustomException(CoreExceptionEnum.ERROR_PARAM);
        }
        if (StrUtil.isBlank(userPwd)) {
            throw new CustomException(CoreExceptionEnum.NO_PWD);
        }
        String md5Code = MD5EncryptionPwdUtil.encryptionMd5(pwd);
        if (!userPwd.equals(md5Code)) {
            return false;
        }
        return true;
    }

    /**
     * @param title
     * @param content
     * @param orderSub
     * @param messageType 1 提车提醒 2 验车提醒 3 中转签收提醒  4 签收提醒  5 交付提醒
     */
    public void addMessage(String title, String content, OrderSub orderSub, int messageType) {
        //禁用之前的提醒
        appMessageService.deleteByOrderId(orderSub.getId());

        //创建提醒
        AppMessageParam param = AppMessageParam.builder()
                .title(title)
                .content(content)
                .orderId(orderSub.getId())
                .orderSubNo(orderSub.getOrderSubNo())
                .isRead(1)
                .messageType(messageType)
                //租户id
                .tenantId(getTenantId())
                .build();
        appMessageService.add(param);
    }


}
